use crate::config::run_setup::log_level::LogLevel;
use crate::util::clap_helper::read_info::ReadInfo;
use crate::util::log_helper::push_error;
use clap::Arg;
use clap::ArgAction;
use clap::Command;

pub static CMD_LOG_LEVEL: once_cell::sync::OnceCell<Option<LogLevel>> =
  once_cell::sync::OnceCell::new();

pub struct CmdResult {
  pub app_list: Vec<String>,
  pub read_info: ReadInfo,
  pub is_clear_cache: bool,
}

fn set_cmd_log_level(arg_matches: &clap::ArgMatches) {
  let default_log_level = String::new();
  let log_level = arg_matches
    .get_one::<String>("log_level")
    .unwrap_or(&default_log_level);
  if !log_level.is_empty() {
    let target_log_level = LogLevel::from_str(log_level.as_str());
    if target_log_level.is_err() {
      CMD_LOG_LEVEL.set(None).expect("cannot set CMD_LOG_LEVEL");
    } else {
      CMD_LOG_LEVEL
        .set(Some(target_log_level.unwrap()))
        .expect("cannot set CMD_LOG_LEVEL");
    }
  } else {
    CMD_LOG_LEVEL.set(None).expect("cannot set CMD_LOG_LEVEL");
  }
}

fn get_app_list(arg_matches: &clap::ArgMatches) -> Vec<String> {
  let raw_app_list = arg_matches
    .get_many::<String>("app_list")
    .unwrap_or_default()
    .map(|v| v.clone())
    .collect::<Vec<_>>();
  let app_list = super::super::vec_helper::vec_set_unique(&raw_app_list);
  return app_list;
}

fn string_option_to_date(string_option: Option<&String>) -> Result<Option<chrono::NaiveDate>, chrono::format::ParseError> {
  if string_option.is_none() {
    return Ok(None);
  }
  let date_string = string_option.unwrap();
  let date_result = chrono::NaiveDate::parse_from_str(date_string, "%Y-%m-%d");
  if date_result.is_err() {
    return Err(date_result.err().unwrap());
  }
  let result = date_result.unwrap();
  return Ok(Some(result));
}

fn get_is_clear_cache(arg_matches: &clap::ArgMatches) -> bool {
  let is_clear_cache = arg_matches.get_one::<bool>("clear_cache").unwrap_or(&false);
  return *is_clear_cache;
}

fn get_read_info(arg_matches: &clap::ArgMatches) -> Option<ReadInfo> {
  let is_read_only = arg_matches.get_one::<bool>("read_only").unwrap_or(&false);
  let read_before_date_str = arg_matches.get_one::<String>("before_date_str");
  let read_after_date_str = arg_matches.get_one::<String>("after_date_str");
  if *is_read_only {
    let before_date = string_option_to_date(read_before_date_str);
    let after_date = string_option_to_date(read_after_date_str);
    let mut is_error = false;
    if before_date.is_err() {
      push_error(format!("read_before_date_str: {read_before_date_str:?} is invalid"));
      is_error = true;
    }
    if after_date.is_err() {
      push_error(format!("read_after_date_str: {read_after_date_str:?} is invalid"));
      is_error = true;
    }
    if is_error {
      return None;
    }
    return Some(ReadInfo {
      is_read_only: true,
      read_before_date_option: before_date.unwrap(),
      read_after_date_option: after_date.unwrap(),
    });
  }
  return Some(ReadInfo {
    is_read_only: false,
    read_before_date_option: None,
    read_after_date_option: None,
  });
}

pub fn build_clap_command() -> CmdResult {
  let arg_matches = Command::new("env-site-log")
    .version("0.1.0")
    .author("env-site-log")
    .about("env-site-log")
    .arg(Arg::new("app_list").action(ArgAction::Append))
    .arg(Arg::new("log_level").short('l').long("log-level"))
    .arg(
      Arg::new("read_only")
        .short('r')
        .long("read-only")
        .action(ArgAction::SetTrue)
        .help("just for reading app-history-log.yml"),
    )
    .arg(
      Arg::new("before_date_str")
       .short('B')
       .long("before")
       .help("just for slice history(log_date) before, only valid for --read-only"),
    )
    .arg(
      Arg::new("after_date_str")
       .short('A')
       .long("after")
       .help("just for slice history(log_date) after, only valid for --read-only"),
    )
    .arg(
      Arg::new("clear_cache")
        .short('C')
        .long("clear-cache")
        .action(ArgAction::SetTrue)
        .help("set cache folder to empty")
    )
    .get_matches();
  let app_list = get_app_list(&arg_matches);
  set_cmd_log_level(&arg_matches);
  get_read_info(&arg_matches);
  let is_clear_cache = get_is_clear_cache(&arg_matches);
  let env_run_at_result = std::env::var("RUN_AT_ENV");
  let read_info = get_read_info(&arg_matches);
  if read_info.is_none() {
    push_error(format!("日期参数不正确.请检查"));
    std::process::exit(1);
  }
  if env_run_at_result.is_ok() {
    let env_run_at = env_run_at_result.unwrap();
    if env_run_at.eq("dev") {
      std::process::exit(0);
    }
  }
  CmdResult { 
    app_list,
    read_info: read_info.unwrap(),
    is_clear_cache
  }
}
